<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="QEe13" id="QEe13"><span data-lake-id="ue1611c23" id="ue1611c23">典型回答</span></h1>
  <p data-lake-id="u345a3b3e" id="u345a3b3e"><br></p>
  <p data-lake-id="u612ec4a4" id="u612ec4a4"><span data-lake-id="ua5292dbc" id="ua5292dbc">序列化是将对象转换为可传输格式的过程。 是一种数据的持久化手段。一般广泛应用于网络传输，RMI和RPC等场景中。 几乎所有的商用编程语言都有序列化的能力，不管是数据存储到硬盘，还是通过网络的微服务传输，都需要序列化能力。</span></p>
  <p data-lake-id="u36b012c6" id="u36b012c6"><span data-lake-id="u731c6857" id="u731c6857">​</span><br></p>
  <p data-lake-id="u9d7ca3bc" id="u9d7ca3bc"><span data-lake-id="ude4ab30c" id="ude4ab30c">在Java的序列化机制中，如果是String，枚举或者实现了</span><span data-lake-id="u365d26dd" id="u365d26dd" style="color: rgb(47, 48, 52)">Serializable</span><span data-lake-id="ub9fc380f" id="ub9fc380f">接口的类，均可以通过Java的序列化机制，将类序列化为符合编码的数据流，然后通过InputStream和OutputStream将内存中的类持久化到硬盘或者网络中；同时，也可以通过反序列化机制将磁盘中的字节码再转换成内存中的类。</span></p>
  <p data-lake-id="ufde980eb" id="ufde980eb"><span data-lake-id="u337d0c61" id="u337d0c61">​</span><br></p>
  <p data-lake-id="u0ee2f912" id="u0ee2f912"><strong><span data-lake-id="uddf686e4" id="uddf686e4">如果一个类想被序列化，需要实现Serializable接口。</span></strong><span data-lake-id="u26c0cbce" id="u26c0cbce">否则将抛出NotSerializableException异常。Serializable接口没有方法或字段，仅用于标识可序列化的语义。</span></p>
  <p data-lake-id="u9a0fb401" id="u9a0fb401"><span data-lake-id="u488bfbc9" id="u488bfbc9">​</span><br></p>
  <p data-lake-id="u85144abd" id="u85144abd"><span data-lake-id="u2621bf41" id="u2621bf41">自定义类通过实现Serializable接口做标识，进而在IO中实现序列化和反序列化，具体的执行路径如下：</span></p>
  <p data-lake-id="u4da18375" id="u4da18375"><span data-lake-id="u86cab61e" id="u86cab61e">​</span><br></p>
  <p data-lake-id="uf4cec12b" id="uf4cec12b"><code data-lake-id="ud898e51f" id="ud898e51f"><span data-lake-id="u0466be83" id="u0466be83">#writeObject -&gt; #writeObject0(判断类是否是自定义类) -&gt; #writeOrdinaryObject(区分Serializable和Externalizable) -&gt; writeSerialData(序列化fields) -&gt; invokeWriteObject(反射调用类自己的序列化策略)</span></code></p>
  <p data-lake-id="u47fb00a9" id="u47fb00a9"><span data-lake-id="u6fffa045" id="u6fffa045">​</span><br></p>
  <p data-lake-id="u86662104" id="u86662104"><span data-lake-id="uf60699d2" id="uf60699d2">其中，在invokeWriteObject的阶段，系统就会处理自定义类的序列化方案。</span></p>
  <p data-lake-id="u2d3da865" id="u2d3da865"><span data-lake-id="uad60b59e" id="uad60b59e">​</span><br></p>
  <p data-lake-id="ufeec765d" id="ufeec765d"><span data-lake-id="uad54a6ac" id="uad54a6ac">这是因为，在序列化操作过程中会对类型进行检查，要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。</span></p>
  <h1 data-lake-id="r576O" id="r576O"><span data-lake-id="uca25d6d5" id="uca25d6d5">知识拓展</span></h1>
  <h2 data-lake-id="bqJoY" id="bqJoY"><span data-lake-id="uff3d36dc" id="uff3d36dc" style="color: var(--yq-text-primary)">Serializable 和 Externalizable 接口有何不同？</span></h2>
  <p data-lake-id="uaba30d61" id="uaba30d61"><span data-lake-id="u258788c1" id="u258788c1" class="lake-fontsize-11" style="color: var(--yq-text-primary)">类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段，仅用于标识可序列化的语义。</span></p>
  <p data-lake-id="u3cca54d8" id="u3cca54d8"><span data-lake-id="u4f0cb97d" id="u4f0cb97d" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u5461945a" id="u5461945a" class="lake-fontsize-11" style="color: var(--yq-text-primary)">当试图对一个对象进行序列化的时候，如果遇到不支持 Serializable 接口的对象。在此情况下，将抛出 NotSerializableException。</span></p>
  <p data-lake-id="u1f185bf4" id="u1f185bf4"><span data-lake-id="u2969f98a" id="u2969f98a" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br>
    如果要序列化的类有父类，要想同时将在父类中定义过的变量持久化下来，那么父类也应该实现java.io.Serializable接口。<br>
    Externalizable继承了Serializable，该接口中定义了两个抽象方法：writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。如果没有在这两个方法中定义序列化实现细节，那么序列化之后，对象内容为空。实现Externalizable接口的类必须要提供一个public的无参的构造器。</span></p>
  <p data-lake-id="u8754cb3c" id="u8754cb3c"><span data-lake-id="u1921a082" id="u1921a082" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="ua0b7dcb6" id="ua0b7dcb6" class="lake-fontsize-11" style="color: var(--yq-text-primary)">所以，实现Externalizable，并实现writeExternal()和readExternal()方法可以指定序列化哪些属性。</span></p>
  <h2 data-lake-id="aLoof" id="aLoof"><span data-lake-id="u95247d7d" id="u95247d7d">如果序列化后的文件或者原始类被篡改，还能被反序列化吗？</span></h2>
  <p data-lake-id="uf453c8db" id="uf453c8db"><br></p>
  <h2 data-lake-id="Fn7Ib" id="Fn7Ib"><span data-lake-id="uc0e09d36" id="uc0e09d36" style="color: var(--yq-text-primary)">在Java中，有哪些好的序列化框架，有什么好处</span></h2>
  <p data-lake-id="u923ed9af" id="u923ed9af"><span data-lake-id="u14d34c13" id="u14d34c13" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Java中常用的序列化框架：</span></p>
  <p data-lake-id="ucc503805" id="ucc503805"><span data-lake-id="u85578598" id="u85578598" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u5d53c518" id="u5d53c518" class="lake-fontsize-11" style="color: var(--yq-text-primary)">java、kryo、hessian、protostuff、gson、fastjson等。</span></p>
  <p data-lake-id="u0c8df916" id="u0c8df916"><span data-lake-id="u3bc4bba2" id="u3bc4bba2" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u06518dc5" id="u06518dc5" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Kryo：速度快，序列化后体积小；跨语言支持较复杂</span></p>
  <p data-lake-id="uc8253acc" id="uc8253acc"><span data-lake-id="ue5a87aed" id="ue5a87aed" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u7b84a577" id="u7b84a577" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Hessian：默认支持跨语言；效率不高</span></p>
  <p data-lake-id="u3d09f9dc" id="u3d09f9dc"><span data-lake-id="u586f83f6" id="u586f83f6" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u9a17dfea" id="u9a17dfea" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Protostuff：速度快，基于protobuf；需静态编译</span></p>
  <p data-lake-id="ua4ae8855" id="ua4ae8855"><span data-lake-id="u7bc82a29" id="u7bc82a29" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u269f8cf7" id="u269f8cf7" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Protostuff-Runtime：无需静态编译，但序列化前需预先传入schema；不支持无默认构造函数的类，反序列化时需用户自己初始化序列化后的对象，其只负责将该对象进行赋值</span></p>
  <p data-lake-id="uf8f95bfc" id="uf8f95bfc"><span data-lake-id="u6b19a87d" id="u6b19a87d" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><span data-lake-id="u8411fd37" id="u8411fd37" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Java：使用方便，可序列化所有类；速度慢，占空间<br><br></span></p>
 </body>
</html>